package main

import (
	"fmt"
	"math"
)

// 如果一个类型实现了一个 interface 中所有方法，我们说类型实现了该 interface，
// 所以所有类型都实现了 empty interface，因为任何一种类型至少实现了 0 个方法。
// go 没有显式的关键字用来实现 interface，只需要实现 interface 包含的方法即可。

// Shape 被任何带有 Area方法 的类型实现
type Shape interface {
	Area() float64
}

// Rectangle has the dimensions of a rectangle.
type Rectangle struct {
	Width  float64
	Height float64
}

// 实现了一个计算面积的方法 Area
func (r Rectangle) Area() float64 {
	return r.Width * r.Height
}

// Perimeter returns the perimeter of a rectangle.
func Perimeter(rectangle Rectangle) float64 {
	return 2 * (rectangle.Width + rectangle.Height)
}

// Circle represents a circle...
type Circle struct {
	Radius float64
}

// Area returns the area of the circle.
func (c Circle) Area() float64 {
	return math.Pi * c.Radius * c.Radius
}

// Triangle represents the dimensions of a triangle.
type Triangle struct {
	Base   float64
	Height float64
}

// Area returns the area of the triangle.
func (c Triangle) Area() float64 {
	return (c.Base * c.Height) * 0.5
}

func main() {
	areaTests := []struct {
		name    string
		shape   Shape
		hasArea float64
	}{
		{name: "Rectangle", shape: Rectangle{Width: 12, Height: 6}, hasArea: 72.0},
		{name: "Circle", shape: Circle{Radius: 10}, hasArea: 314.1592653589793},
		{name: "Triangle", shape: Triangle{Base: 12, Height: 6}, hasArea: 36.0},
		// 这里可以添加 任何实现了 Area 方法的 struct，都可以调用 Area 方法
	}

	var shape Shape
	var circle = Circle{Radius: 10}
	shape = &circle

	// 判断 某个类型是不是 实现了某个 interface
	if t, ok := shape.(*Circle); ok {
		fmt.Println("====================")
		fmt.Println("Circle implements Shape", t)
		fmt.Println("====================")
	} else {
		fmt.Println("====================")
		fmt.Println(t)
	}

	for _, tt := range areaTests {
		got := tt.shape.Area()
		if got != tt.hasArea {
			fmt.Sprintf("%#v got %g want %g", tt.shape, got, tt.hasArea)
		}
	}
}
